using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Think.Problems.Solitaire;

namespace Think.Test.Problems.Solitaire
{
    [TestClass]
    public class SolitaireRuleTest
    {
        [TestMethod]
        public void CheckWhetherCardsCanBeSet()
        {
            // Setup
            var rule = new SolitaireRule();
            var bases = new[] { "2C", "9D", "QH", "3S" };
            var cards = new[] { "AH", "8C", "JS", "2D" };

            // Execute
            var results = bases.Zip(cards, (b, c) => rule.CanSet(b, c));

            // Assert
            Assert.IsTrue(results.All(i => i));
        }

        [TestMethod]
        public void CheckWhetherCardsCanBeSetThatCannot()
        {
            // Setup
            var rule = new SolitaireRule();
            var bases = new[] { "3C", "7D", "QS", "3H" };
            var cards = new[] { "AH", "8C", "JS", "2D" };

            // Execute
            var results = bases.Zip(cards, (b, c) => rule.CanSet(b, c));

            // Assert
            Assert.IsTrue(results.All(i => !i));   
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CallCanSetWithNullBase()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            rule.CanSet(a_base: null, a_travelling: "AD");

        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CallCanSetWithNullTravelling()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            rule.CanSet("2H", a_travelling: null);

        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void CallCanSetWithInvalidBase()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            rule.CanSet("Fish Sticks", "JH");
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void CallCanSetWithInvalidTravelling()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            rule.CanSet("QD", "Custard");
        }

        [TestMethod]
        public void CallCanSetOnEmptyWithKing()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            var result = rule.CanSetOnEmpty("KD");

            // Assert
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void CallCanSetOnEmptyWithNonKing()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            var result = rule.CanSetOnEmpty("KD");

            // Assert
            Assert.IsTrue(result);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CallCanSetOnEmptyWithNull()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            rule.CanSetOnEmpty(null);
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void CallCanSetOnEmptyWithInvalidCard()
        {
            // Setup
            var rule = new SolitaireRule();

            // Execute
            rule.CanSetOnEmpty("42");
        }
    }
}